Many fixes and cleanups for lomount:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 2 Mar 2006 20:35:17 +0000 (21:35 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 2 Mar 2006 20:35:17 +0000 (21:35 +0100)
- Fixed several overflows, off-by-one, and uninitialized variables.
- Added well-defined exit codes.
- Proper handling of system()'s return value.
- Errors parsing partition table cause it to stop now.
- etcetera...

Tested on 32 and 64 bit, with valgrind, with physical disks and disk
images.

Signed-off-by: Charles Coffing <ccoffing@novell.com>
tools/misc/lomount/lomount.c

index 308b772d46e8e5ef7dec3af7d091c1bd81079554..b72f77da0361af8e2c2c9359809ede4ec8b38a61 100644 (file)
  * THE SOFTWARE.
  */
 
+/*
+ *  Return code:
+ *
+ *  bit 7 set:         lomount wrapper failed
+ *  bit 7 clear:       lomount wrapper ok; mount's return code in low 7 bits
+ *  0                  success
+ */
+
+enum
+{
+       ERR_USAGE = 0x80,       // Incorrect usage
+       ERR_PART_PARSE,         // Failed to parse partition table
+       ERR_NO_PART,            // No such partition
+       ERR_NO_EPART,           // No such extended partition
+       ERR_MOUNT               // Other failure of mount command
+};
+
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
+#include <sys/wait.h>
 #include <errno.h>
 
 #define BUF 4096
 
-//#define SECSIZE 4096    /* arbitrarilly large (it's probably just 512) */
 #define SECSIZE 512
 
 struct pentry 
@@ -50,30 +67,32 @@ struct pentry
        unsigned long no_of_sectors_abs;
 };
 
-char * progname;
-
-int loadptable(const char *argv, struct pentry parttbl[], struct pentry **exttbl)
+int loadptable(const char *diskimage, struct pentry parttbl[], struct pentry **exttbl, int * valid)
 {
-       FILE *fd; 
-       int i, valid, total_known_sectors = 0;
+       FILE *fd;
+       size_t size;
+       int fail = 1;
+       int i, total_known_sectors = 0;
        unsigned char *pi; 
        unsigned char data [SECSIZE]; 
        unsigned long extent = 0, old_extent = 0, e_count = 1;
        struct pentry exttbls[4];
 
-       fd = fopen(argv, "r");
+       *valid = 0;
+
+       fd = fopen(diskimage, "r");
        if (fd == NULL)
        {
-               perror ("lomount"); 
-               return 1;
+               perror(diskimage);
+               goto done;
        }
-       i = fread (&data, 1, sizeof (data), fd); 
-       if (i < SECSIZE)
+       size = fread (&data, 1, sizeof(data), fd);
+       if (size < (size_t)sizeof(data))
        {
-               fprintf (stderr, "%s: could not read the entire first sector\n", progname); 
-               return 1;
+               fprintf(stderr, "Could not read the entire first sector of %s.\n", diskimage);
+               goto done;
        }
-       for (i = 0;i < 4;i++)
+       for (i = 0; i < 4; i++)
        {
                pi = &data [446 + 16 * i];
                parttbl [i].bootable = *pi; 
@@ -95,7 +114,7 @@ int loadptable(const char *argv, struct pentry parttbl[], struct pentry **exttbl
                        old_extent = extent;
                }
        }
-       valid = (data [510] == 0x55 && data [511] == 0xaa) ? 1 : 0;
+       *valid = (data [510] == 0x55 && data [511] == 0xaa) ? 1 : 0;
        for (i = 0; i < 4; i++)
        {
                total_known_sectors += parttbl[i].no_of_sectors_abs;
@@ -105,7 +124,7 @@ int loadptable(const char *argv, struct pentry parttbl[], struct pentry **exttbl
 #ifdef DEBUG
        if (extent != 0)
        {
-               printf("extended partition detected at offset %d\n", extent);
+               printf("extended partition detected at offset %ld\n", extent);
        }
 #endif
        while (extent != 0)
@@ -113,14 +132,14 @@ int loadptable(const char *argv, struct pentry parttbl[], struct pentry **exttbl
 /* according to realloc(3) passing NULL as pointer is same as calling malloc() */
                exttbl[0] = realloc(exttbl[0], e_count * sizeof(struct pentry));
                fseek(fd, extent, SEEK_SET);
-               i = fread (&data, 1, sizeof (data), fd); 
-               if (i < SECSIZE)
+               size = fread (&data, 1, sizeof(data), fd);
+               if (size < (size_t)sizeof(data))
                {
-                       fprintf (stderr, "%s: could not read the entire first sector\n", progname); 
-                       return 1;
+                       fprintf(stderr, "Could not read extended partition of %s.", diskimage);
+                       goto done;
                }
        /* only first 2 entrys are used in extented partition tables */
-               for (i = 0;i < 2;i++)
+               for (i = 0; i < 2; i++)
                {
                        pi = &data [446 + 16 * i];
                        exttbls [i].bootable = *pi; 
@@ -152,7 +171,7 @@ int loadptable(const char *argv, struct pentry parttbl[], struct pentry **exttbl
                        /* adjust for start of image instead of start of ext partition */
                                exttbl[0][e_count-1].start_sector_abs += (extent/SECSIZE);
 #ifdef DEBUG
-                               printf("extent %d start_sector_abs %d\n", extent, exttbl[0][e_count-1].start_sector_abs);
+                               printf("extent %ld start_sector_abs %ld\n", extent, exttbl[0][e_count-1].start_sector_abs);
 #endif
                        //else if (parttbl[i].system == 0x5)
                        }
@@ -165,53 +184,71 @@ int loadptable(const char *argv, struct pentry parttbl[], struct pentry **exttbl
                }
                e_count ++;
        }
-       //fclose (fd);
-       //the above segfaults (?!!!)
 #ifdef DEBUG
-       printf("e_count = %d\n", e_count);
+       printf("e_count = %ld\n", e_count);
 #endif
-       return valid;
+       fail = 0;
+
+done:
+       if (fd)
+               fclose(fd);
+       return fail;
+}
+
+void usage()
+{
+       fprintf(stderr, "You must specify at least -diskimage and -partition.\n");
+       fprintf(stderr, "All other arguments are passed through to 'mount'.\n");
+       fprintf(stderr, "ex. lomount -t fs-type -diskimage hda.img -partition 1 /mnt\n");
+       exit(ERR_USAGE);
 }
 
 int main(int argc, char ** argv)
 {
+       int status;
        struct pentry perttbl [4];
        struct pentry *exttbl[1], *parttbl;
-       char buf[BUF], argv2[BUF], diskimage[BUF];
-       int partition = 1, sec, num = 0, pnum = 0, len = BUF, i, f = 0, valid;
-       progname = argv[0];
+       char buf[BUF], argv2[BUF];
+       const char * diskimage = 0;
+       int partition = 0, sec, num = 0, pnum = 0, i, valid;
+       size_t argv2_len = sizeof(argv2);
+       argv2[0] = '\0';
        exttbl[0] = NULL;
+
        for (i = 1; i < argc; i ++)
        {
-               if (strncmp(argv[i], "-diskimage", BUF)==0)
+               if (strcmp(argv[i], "-diskimage")==0)
                {
-                       strncpy(diskimage, argv[i+1], BUF);
-                       i++; f = 1;
+                       if (i == argc-1)
+                               usage();
+                       i++;
+                       diskimage = argv[i];
                }
-               else if (strncmp(argv[i], "-partition", BUF)==0)
+               else if (strcmp(argv[i], "-partition")==0)
                {
-                       partition = atoi(argv[i+1]);
+                       if (i == argc-1)
+                               usage();
                        i++;
-                       if (partition < 1) partition = 1;
+                       partition = atoi(argv[i]);
                }
                else
                {
-                       strncat(argv2, argv[i], len);
-                       strncat(argv2, " ", len-1);
-                       len -= strlen(argv[i]);
-                       len--;
+                       size_t len = strlen(argv[i]);
+                       if (len >= argv2_len-1)
+                               usage();
+                       strcat(argv2, argv[i]);
+                       strcat(argv2, " ");
+                       len -= (len+1);
                }
        }
-       if (!f)
-       {
-               printf("You must specify -diskimage and -partition\n");
-               printf("ex. lomount -t fs-type -diskimage hda.img -partition 1 /mnt\n");
-               return 0;
-       }
-       valid = loadptable(diskimage, perttbl, exttbl);
+       if (! diskimage || partition < 1)
+               usage();
+
+       if (loadptable(diskimage, perttbl, exttbl, &valid))
+               return ERR_PART_PARSE;
        if (!valid)
        {
-               printf("Warning: disk image does not appear to describe a valid partition table.\n");
+               fprintf(stderr, "Warning: disk image does not appear to describe a valid partition table.\n");
        }
        /* NOTE: need to make sure this always rounds down */
        //sec = total_known_sectors / sizeof_diskimage;
@@ -228,14 +265,14 @@ off by (larger than) a value less than one. */
        {
                if (exttbl[0] == NULL)
                {
-                   printf("No extended partitions were found in %s.\n", diskimage);
-                   return 2;
+                   fprintf(stderr, "No extended partitions were found in %s.\n", diskimage);
+                   return ERR_NO_EPART;
                }
                parttbl = exttbl[0];
                if (parttbl[partition-5].no_of_sectors_abs == 0)
                {
-                       printf("Partition %d was not found in %s.\n", partition, diskimage);
-                       return 3;
+                       fprintf(stderr, "Partition %d was not found in %s.\n", partition, diskimage);
+                       return ERR_NO_PART;
                }
                partition -= 4;
        }
@@ -244,8 +281,8 @@ off by (larger than) a value less than one. */
                parttbl = perttbl;
                if (parttbl[partition-1].no_of_sectors_abs == 0)
                {
-                       printf("Partition %d was not found in %s.\n", partition, diskimage);
-                       return 3;
+                       fprintf(stderr, "Partition %d was not found in %s.\n", partition, diskimage);
+                       return ERR_NO_PART;
                }
        }
        num = parttbl[partition-1].start_sector_abs;
@@ -253,10 +290,14 @@ off by (larger than) a value less than one. */
 #ifdef DEBUG
        printf("offset = %d\n", pnum);
 #endif
-       snprintf(buf, BUF, "mount -oloop,offset=%d %s %s", pnum, diskimage, argv2);
+       snprintf(buf, sizeof(buf), "mount -oloop,offset=%d %s %s", pnum, diskimage, argv2);
 #ifdef DEBUG
        printf("%s\n", buf);
 #endif
-       system(buf);
-       return 0;
+       status = system(buf);
+       if (WIFEXITED(status))
+               status = WEXITSTATUS(status);
+       else
+               status = ERR_MOUNT;
+       return status;
 }